/*
 * @Author: liuzelin
 * @Date: 2023-01-29 10:43:35
 * @LastEditors: liuzelin
 * @LastEditTime: 2023-01-30 16:50:38
 * @Description: file content
 */
#include "panda.hpp"

#include <vector>
#include <functional>
#include <iostream>
#include <thread>

using namespace std;
using namespace Panda;

struct TestTask {
    TestTask( uint64_t delay ) :ms( delay ) {}
    TestTask( TestTask& other ) = default;
    TestTask( TestTask&& other ) = default;
    TestTask() = default;
    uint64_t ms;
};
typedef std::multimap<uint64_t, TestTask> TestTasks;


void TestTime()
{
    int i = 100;
    while (i--)
    {
        cout <<  Panda::Time::NowStr() << " " << Panda::Time::NowMs()<< endl;
        this_thread::sleep_for(chrono::milliseconds(100));
    }
}

void TestLog(){
    Panda::LogHandler::Instance().SetWriteFileName(true);
    int i = 100;
    while (i--)
    {
        LOG(Info) << "Test Log";
        this_thread::sleep_for(chrono::milliseconds(100));
    }
}

void TestSTDEvent()
{
    Panda::Event* e = Panda::Event::CreatePandaEvent();
    thread s([&]
             { e->Wait(1000); 
        LOG(Info) <<  Panda::Time::NowStr() << " Wait Been Set"; });
    this_thread::sleep_for(chrono::milliseconds(100));
    LOG(Info) << Panda::Time::NowStr() << " Set Wait";
    e->Set();
    s.join();
}



void TestThreadManager()
{
    Thread *thread = ThreadManager::Instance()->Current();
    Thread* newThread = ThreadManager::Instance()->CreateThread();
    newThread->SetThreadName("TestThread");
    newThread->Start();
    static std::function<void()> Func;
    static auto Func1 = [&]()
    {
        static int i = 0;
        LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" Thread Test:" << i++;
        thread->PostDelayTask(PandaFromHere,[&]()
                              {
            static int i = 0;
            std::function<void()> func = Func;
            LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" Thread Test:" << i++; 
            newThread->PostDelayTask(PandaFromHere,std::move(func), 100); },
                              100);
    };
    Func = Func1;

    std::function<void()> func = Func;
    newThread->PostDelayTask(PandaFromHere,std::move(func), 100);

    newThread->PostDelayTask(PandaFromHere,[&]() {
        LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" StopLoop";
        thread->Stop();
    }, 10000);
    
    LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" StartLoop";
    thread->Start();
    newThread->Stop();
    delete newThread;
}

void TestTCPSocket()
{
    class ClientListener : public TCPSocketListener
    {
    public:
        virtual void OnRead(char *data, size_t len){
            if (isServer)
            {
                if (clinet_->Send(data, len) == 0)
                {
                    LOG(Info) << prex_ << " OnRead:" << std::string(data,len).c_str() << " Send Success";
                }
            } else {
                LOG(Info) << prex_ << " OnRead:" << std::string(data, len).c_str();
            }
        }
        virtual void OnNewConnect(TCPSocket* s) {
            isServer = true;
            clinet_ = s;
        }
        void OnSend(char*, size_t, int) {

        }
        virtual void OnConnected(TCPSocket *s){
            LOG(Info) << "OnConnected To Server:" << s->GetRemote().ToString();
            clinet_ = s;
            clinet_->SetSocketListener(this);
        }
        
        ~ClientListener(){
            if (isServer && clinet_)
            {
                delete clinet_;
                clinet_ = nullptr;
            }
        }
        std::string prex_ = "Client";
        TCPSocket* clinet_ = nullptr;
        bool isServer = false;
    };
    ClientListener serverListener;
    ClientListener clientListener;
    Thread *client_thread =ThreadManager::Instance()->Current();
    Thread* server_thread = ThreadManager::Instance()->CreateThread();
    server_thread->SetThreadName("TCPServer");
    server_thread->Start();
    
    std::unique_ptr<TCPSocket> cli(client_thread->CreateTCPSocket());
    cli->SetSocketListener(&clientListener);

    std::unique_ptr<TCPSocket> ser(server_thread->CreateTCPSocket());
    SocketAddress serverAddress("127.0.0.1", 8010);
    ser->SetSocketListener(&serverListener);
    ser->Bind(serverAddress);
    ser->Listen();
    volatile bool stop =false;
    
    
    static std::function<void()> Func;
    static auto ClientFunc = [&](){
        if (stop)
            return;
        do{
            if (clientListener.clinet_ == nullptr)
                break;
            std::stringstream ss;
            ss << Time::NowStr() << " Tcp Test";
            LOG(Info) <<ThreadManager::Instance()->Current()->Name()<< ss.str();
            cli->Send(ss.str().data(), ss.str().length());
        } while(0);
        if (stop == false)
        {
            std::function<void()> func = Func;
            client_thread->PostDelayTask(PandaFromHere,std::move(func), 100);
        }
    };
    Func = ClientFunc;
    std::function<void()> func = Func;
    client_thread->PostDelayTask(PandaFromHere,std::move(func),100);
    cli->Connect(serverAddress);

    server_thread->PostDelayTask(PandaFromHere,[&]() {
        LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" Socket Test Stop";
        stop = false;
        ser.release();
        client_thread->Invoke(PandaFromHere,[&]() {cli.release(); });
        client_thread->Stop();
    }, 10000);
    
    LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" Socket Test Loop Start";
    client_thread->Start();
    LOG(Info) <<ThreadManager::Instance()->Current()->Name() << " Socket Test Loop Exit";
    server_thread->Stop();
    delete server_thread;
}

void TestUDPSocket()
{
    class UDPListener : public UDPSocketListener
    {
        public:
        void OnReadFrom(char *data, size_t len, const SocketAddress &from)
        {

            LOG(Info) <<ThreadManager::Instance()->Current()->Name() << (isServer ? "Server " : "Client ") << " Recv From:" << from.ToString() << " -> " << std::string(data, len).c_str();
            if (isServer && socket)
            {
                SocketAddress to = from;
                socket->SendTo(data, len, to);
            }
        }
        void OnSend(char*, size_t, int, const char*){}
        bool isServer = false;
        UDPSocket *socket = nullptr;
    };

    UDPListener sListener;
    sListener.isServer = true;

    UDPListener cListener;
    Thread* client_thread = ThreadManager::Instance()->Current();
    Thread* server_thread = ThreadManager::Instance()->CreateThread();
    server_thread->SetThreadName("UDPServer");
    server_thread->Start();
    
    std::unique_ptr<UDPSocket> cli(client_thread->CreateUDPSocket());
    cli->SetSocketListener(&cListener);
    cListener.socket = cli.get();
    SocketAddress clientAddress("127.0.0.1",8001);
    SocketAddress serverAddress("127.0.0.1",9001);
    cli->Bind(clientAddress);
    
    std::unique_ptr<UDPSocket> ser(server_thread->CreateUDPSocket());
    ser->SetSocketListener(&sListener);
    ser->Bind(serverAddress);
    sListener.socket = ser.get();
    volatile bool stop =false;
    
    static std::function<void()> Func;
    static auto ClientFunc = [&](){
        if (stop)
            return;
        do{
            std::stringstream ss;
            ss << Time::NowStr() << " UDP Test";
            LOG(Info) <<ThreadManager::Instance()->Current()->Name()<< ss.str();
            cli->SendTo(ss.str().data(), ss.str().length(),serverAddress);
        } while(0);
        if (stop == false)
        {
            std::function<void()> func = Func;
            client_thread->PostDelayTask(PandaFromHere,std::move(func), 100);
        }
    };
    Func = ClientFunc;
    std::function<void()> func = Func;
    client_thread->PostDelayTask(PandaFromHere,std::move(func), 100);

    server_thread->PostDelayTask(PandaFromHere,[&]() {
        LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" UDP Socket Test Stop";
        stop = false;
        ser.release();
        client_thread->Invoke(PandaFromHere,[&]() {cli.release(); });
        client_thread->Stop();
    }, 10000);
    
    LOG(Info) <<ThreadManager::Instance()->Current()->Name()<<" UDP Socket Test Start";
    client_thread->Start();
    server_thread->Stop();
}

void TestByteReadWrite(){
    uint8_t buffer[4] = {0};
    uint32_t v1 = 0x12345678;
    Panda::ByteReaderWriter<uint32_t>::WriteByte(buffer,v1);
    uint32_t v2 = Panda::ByteReaderWriter<uint32_t>::ReadByte(buffer);

    LOG(Info) << "v1:" << v1;
    LOG(Info) << "v2:" << v2;
    LOG(Info) << "buffer:" << (uint32_t)buffer[0] << "-" << (uint32_t)buffer[1] << "-"<< (uint32_t)buffer[2] << "-"<< (uint32_t)buffer[3];
}

void TestMemoryPool() {
    std::vector<void*> ptrs;
    LOG(Info) << "========Pool Start========";
    {
        Panda::DataPool pool;
        for (int i = 0;i<512*1024;i++){
            ptrs.emplace_back(pool.malloc(i%2048 + 1));
            memset(ptrs.back(),i,1);
            if (i % 5 ==0) {
                int j = 5;
                while(ptrs.empty() == false && j-- != 0){
                    int i = rand()%ptrs.size();
                    pool.free(ptrs[i]);
                    ptrs.erase(ptrs.begin()+i);
                }
            }
        }
        while (ptrs.empty() == false) {
            pool.free(ptrs.back());
            ptrs.pop_back();
        }
    }
    LOG(Info) << "========Pool End========";
    for (int i = 0;i<512*1024;i++){
        ptrs.emplace_back(malloc(i%2048));
        if (i % 5 ==0) {
            int j = 5;
            while(ptrs.empty() == false && j-- != 0){
                int i = rand()%ptrs.size();
                free(ptrs[i]);
                ptrs.erase(ptrs.begin()+i);
            }
        }
    }
    while (ptrs.empty() == false) {
        free(ptrs.back());
        ptrs.pop_back();
    }
    LOG(Info) << "========Os End========";

}

void TestResolve(){
  auto resolver_thread = ThreadManager::Instance()->CreateThread();
  resolver_thread->SetThreadName("ResolverThread");
  resolver_thread->Start();
  auto resolver = resolver_thread->CreateResolver();
  char* ips[10] = { nullptr };
  for (int i = 0; i < 10; i++) {
      ips[i] = (char*)malloc(256);
      memset(ips[i], 0, 256);
  }
  int ret = resolver->AsyncResolver("baidu.com", ips, 10);
  for (int i = 0; i < ret;i++) {
    LOG(Info) << "baidu.com Resolve:" << i << " " << ips[i];
  }
  for (int i = 0; i < 10; i++) {
      free(ips[i]);
  }
  resolver_thread->Stop();
  delete resolver;
}

vector<function<void(void)>> TestFuncs = { \
    /*TestUDPSocket,\
    TestTCPSocket,\
    TestThreadManager,\
    TestSTDEvent,       \
    TestLog,        \
    TestTime,       \
    TestByteReadWrite, \*/
    TestResolve,\
    TestMemoryPool};

int main()
{
    Panda::LogHandler::Instance().SetWriteFileName(false);
    // for(auto f: TestFuncs)
    // {
    //     f();
    // }
    TestTasks tasks;
    uint64_t k = 0;
    tasks.emplace( std::make_pair( k, TestTask() ) );
    return 0;
}
